package ElasticSearch

import (
	"context"
	"encoding/json"
	"github.com/olivere/elastic/v7"
	"reflect"
	"time"
)

//ElasticRepository 仓储
type ElasticRepository struct {
	content   *ElasticContent
	tableName string
	typ       reflect.Type
	timeout   time.Duration
}

//Add 插入单个
// id id值
// entity  结构体
func (e *ElasticRepository) Add(id string, entity interface{}) (res *elastic.IndexResponse,err error) {
	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.Index().
		Index(e.content.index).
		Type(e.tableName).
		Id(id).
		BodyJson(entity).
		Do(ctx)
	if err != nil {
		return nil, err
	}
	return response, nil
}

//AddMany 插入多个
// entityMap【id值】结构体
func (e *ElasticRepository) AddMany(entityMap map[string]interface{}) (res *elastic.BulkResponse,err error) {

	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	bulkRequest := e.content.client.Bulk().
		Index(e.content.index).
		Type(e.tableName)
	for key, subject := range entityMap {		
		doc := elastic.NewBulkIndexRequest().Id(key).Doc(subject)
		bulkRequest = bulkRequest.Add(doc)
	}
	response, err := bulkRequest.Do(ctx)
	if err != nil {
		return nil, err
	}
	return response, nil
}

//Remove 删除
// ids id值
func (e *ElasticRepository) Remove(ids ...string) (res *elastic.BulkResponse,err error){
	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	bulkRequest := e.content.client.Bulk().
		Index(e.content.index).
		Type(e.tableName)
	for _,id := range ids {
		doc := elastic.NewBulkDeleteRequest().Id(id)
		bulkRequest = bulkRequest.Add(doc)
	}
	response,err := bulkRequest.Do(ctx)
	if err != nil {
		return nil, err
	}
	return response, nil
}

//Set 更新
//id     文档id
//doc    更新内容
func (e *ElasticRepository) Set(id string, doc map[string]interface{}) (res *elastic.UpdateResponse,err error){
	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.Update().
		Index(e.content.index).
		Type(e.tableName).
		Id(id).
		Doc(doc).
		Do(ctx)
	if err != nil {
		return nil, err
	}
	return response, nil
}

//SetMany 更新多个
// entityMap【id值】结构体
func (e *ElasticRepository) SetMany(entityMap map[string]interface{}) (res *elastic.BulkResponse,err error) {

	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	bulkRequest := e.content.client.Bulk().
		Index(e.content.index).
		Type(e.tableName)
	for key, subject := range entityMap {
		doc := elastic.NewBulkUpdateRequest().Id(key).Doc(subject)
		bulkRequest = bulkRequest.Add(doc)
	}
	response, err := bulkRequest.Do(ctx)
	if err != nil {
		return nil, err
	}
	return response, nil
}

//GetById 查询单个
// id         id值
// entity      查询的结果
func (e *ElasticRepository) GetById(id string, entity interface{}) error{

	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.Get().
		Index(e.content.index).
		Type(e.tableName).
		Id(id).
		Do(ctx)
	if err != nil {
		return err
	}
	if response.Found {
		err := json.Unmarshal(response.Source, entity)
		if err!= nil {
			return  err
		}
		return nil
	}
	return nil
}

//Query 查询
//query  查询条件
//返回 搜索结果不处理
func  (e *ElasticRepository) Query(query elastic.Query)(result *elastic.SearchResult,err error) {

	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.
		Search(e.content.index).
		Type(e.tableName).
		Query(query).
		Do(ctx)

	if err != nil {
		return nil, err
	}
	return response, nil
}

// Search    搜索
// query     查询条件
// entityTyp 结果集转换类型对应  entity []interface{} 中 interface{} 类型
// 搜索返回具体结果
func (e *ElasticRepository) Search(query elastic.Query) (entity []interface{},totalCount int64, err error) {
	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.
		Search(e.content.index).
		Type(e.tableName).
		Query(query).
		Do(ctx)
	if err != nil {
		return nil,0, err
	}
	return response.Each(e.typ),response.TotalHits(), nil
}

//SearchPage 搜索结果分页显示((pageSize-1)*pageIndex <= 10000,大于则获取不到内容)
//query      查询条件
//pageIndex  当前页，从1开始
//pageSize   每页多少条
//entity     当前页详细数据
//totalCount 页总数
func (e *ElasticRepository) SearchPage(query elastic.Query,pageIndex,pageSize int) (entity []interface{},totalCount int64,err error) {

	ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
	defer cancel()

	response, err := e.content.client.
		Search(e.content.index).
		Type(e.tableName).
		Query(query).
		From((pageIndex - 1) * pageSize).
		Size(pageSize).
		Do(ctx)
	if err != nil {
		return nil, 0, err
	}
	return response.Each(e.typ), response.TotalHits(), nil
}
